﻿#include <Sys\RenderUnit\SysRenderDatagram\MUTITEXTURERD.HPP>
#include <Render\Render_Win32\Render_Win32_OpenGL\RENDER_WIN32_OPENGL.HPP>
#include <Sys\RenderUnit\SYSDDCLASSID.HPP>
#include <Sys\RenderUnit\SysDatagramDisposal_OpenGL\VERTEXREGISTRYDDOPENGL.HPP>
#include <Sys\RenderUnit\SysDatagramDisposal_OpenGL\POSTDRAWDDOPENGL.HPP>
#include <Sys\RenderUnit\SysDatagramDisposal_OpenGL\STAGEDDPENGL.HPP>

using namespace CxxlMan;
using namespace Cxxl3D;




class CMutiTextureDD_OpenGL:public IDatagramDisposal_OpenGL, public IPostDrawNotice, public IMutiTextureBridge
{
  unsigned long m_ITextureRD_AttrBox_Num;

  //Smart_Ptr<IVertexRegistryDDOpenGL> m_IVertexRegistryDDOpenGL_Ptr;
  Smart_Ptr<IStageDDOpenGL> m_IStageDDOpenGL_Ptr;
  Smart_Ptr<IPostDrawDDOpenGL> m_IPostDrawDDOpenGL_Ptr;

  // IPostDrawDDOpenGL 經此函數通知
  virtual void cxxlFASTCALL Notice()
  {
    MutiTextureDD_OpenGL_Clear();    
    m_IPostDrawDDOpenGL_Ptr->Del(this);
  }

  // 清除 MutiTexture 恢復內定值
  void cxxlFASTCALL MutiTextureDD_OpenGL_Clear()
  {
    if(m_ITextureRD_AttrBox_Num == 0)
      return;

    glActiveTexture(GL_TEXTURE0_ARB);
    glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); // 恢復 OpenGL 的預設

    glMatrixMode(GL_TEXTURE);
    // glLoadMatrixf( (const float *)&(C3DMatrix4x4)Matrix4x4::IdentityCreate() );
    glLoadIdentity();

    // glClientActiveTexture(GL_TEXTURE0_ARB);
    // glDisableClientState(GL_TEXTURE_COORD_ARRAY);

    for(int n = 1; n < m_ITextureRD_AttrBox_Num; ++n)
    {
      glActiveTexture(GL_TEXTURE0_ARB+n);
      glMatrixMode(GL_TEXTURE);
      //glLoadMatrixf( (const float *)&(C3DMatrix4x4)Matrix4x4::IdentityCreate() );
      glLoadIdentity();
      
      glClientActiveTexture(GL_TEXTURE0_ARB+n);
      glDisableClientState(GL_TEXTURE_COORD_ARRAY);

      // 關閉 Stage
      glDisable( GL_TEXTURE_2D );
      glDisable( GL_TEXTURE_CUBE_MAP );
    }

    glActiveTexture(GL_TEXTURE0_ARB);
    m_ITextureRD_AttrBox_Num = 0;
  }

/*
  void cxxlFASTCALL doBlendMode(unsigned char BlendMode)
  {
    switch(BlendMode)
    {
    case 1:      
      glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
      break;
    case 2:      
      glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
      break;
    default:
      glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
    };
  }
*/

  virtual bool cxxlFASTCALL Exec(const Smart_Ptr<IRenderDatagramDisposalCenterOpengl> &IRenderDatagramDisposalCenter_Arg,
    const Smart_Ptr<IRenderDatagram> &IRenderDatagram_Arg, const CxxlMan::CSmart_Ptr<Matrix4x4> &ViewMatrix_Arg)
  {

    // 第一次被叫用才會取得
    // if(m_IVertexRegistryDDOpenGL_Ptr.isNULL())
    //   m_IVertexRegistryDDOpenGL_Ptr =  Smart_Cast<IVertexRegistryDDOpenGL>(IRenderDatagramDisposalCenter_Arg->GetIDatagramDisposal_OpenGL(IVertexRegistryOpenGL_ClassID));

    // 第一次被叫用才會取得
    if(m_IStageDDOpenGL_Ptr.isNULL())
      m_IStageDDOpenGL_Ptr = Smart_Cast<IStageDDOpenGL>(IRenderDatagramDisposalCenter_Arg->GetIDatagramDisposal_OpenGL(IStageOpenGL_ClassID));

    // 第一次被叫用才會取得
    if(m_IPostDrawDDOpenGL_Ptr.isNULL())
      m_IPostDrawDDOpenGL_Ptr = Smart_Cast<IPostDrawDDOpenGL>(IRenderDatagramDisposalCenter_Arg->GetIDatagramDisposal_OpenGL(IPostDrawDDOpenGL_ClassID));

    m_IPostDrawDDOpenGL_Ptr->Add(this);

    // 取得目前登記作用中的 IVertexDD
    // Smart_Ptr<IVertexDD> IVertexDD_Ptr = m_IVertexRegistryDDOpenGL_Ptr->Get();    



    Smart_Ptr<IMutiTextureRD> IMutiTextureRD_Ptr = (IMutiTextureRD*)GetDefaultInterface(IRenderDatagram_Arg);
    Smart_Ptr<cxxlList<ITextureRD_AttrBox> > ITextureRD_AttrBox_List = GetTextureRDList(IMutiTextureRD_Ptr);

    m_ITextureRD_AttrBox_Num = ITextureRD_AttrBox_List->GetCount();
    if(m_ITextureRD_AttrBox_Num == 0)
      return true;


    // CVertexDDOpenGL.cpp 的 U,V 貼圖座標須先設定過
    // GLvoid *pTexturePointer;
    // glGetPointerv(GL_TEXTURE_COORD_ARRAY_POINTER, &pTexturePointer);

    ITextureRD_AttrBox_List->ResetPT(toHead);
    for(unsigned long n = 0; n < m_ITextureRD_AttrBox_Num; ++n)
    {
      m_IStageDDOpenGL_Ptr->SetStage(n); // 記錄現處 Stage

      Smart_Ptr<ITextureRD> ITextureRD_Ptr(NULL);
      Smart_Ptr<ITextureRD_AttrBox> ITextureRD_AttrBox_Ptr = (*ITextureRD_AttrBox_List)++;
      ITextureRD_AttrBox_Ptr->Get(ITextureRD_Ptr);
      if(ITextureRD_Ptr.isNULL())
        continue;

      // glClientActiveTexture(GL_TEXTURE0_ARB+n);
      // glEnableClientState(GL_TEXTURE_COORD_ARRAY); // 不知是不是須再加上這句
      // glTexCoordPointer(2,GL_FLOAT,IVertexDD_Ptr->Get_VertexSize(),pTexturePointer); 

      glActiveTexture(GL_TEXTURE0_ARB+n);

      if(IRenderDatagramDisposalCenter_Arg->Exec((ITextureRD*)ITextureRD_Ptr, ViewMatrix_Arg) == false)
      {
        m_IStageDDOpenGL_Ptr->SetStage(0);
        MutiTextureDD_OpenGL_Clear();
        return false;
      }

/*
      doBlendMode(BlendMode);

      glMatrixMode(GL_TEXTURE);
      if(TextureMatrix_cPtr.isNULL() == false)
	      glLoadMatrixf( (const float *) (const C3DMatrix4x4*)TextureMatrix_cPtr );
      else
      {
        glLoadIdentity();
      }
*/
    }

    // glActiveTexture(GL_TEXTURE0_ARB);
    m_IStageDDOpenGL_Ptr->SetStage(0);
    return true;
  }

public:
  // Constructor
  CMutiTextureDD_OpenGL()
    :cxxlObject(Spirit_Easy),
//    m_IVertexRegistryDDOpenGL_Ptr(NULL,this),
    m_IStageDDOpenGL_Ptr(NULL,this),
    m_IPostDrawDDOpenGL_Ptr(NULL,this)
  {
    m_ITextureRD_AttrBox_Num = 0;
  }

  // Destructor
  virtual ~CMutiTextureDD_OpenGL()
  {
  }

};

cxxlObject *cxxlFASTCALL New_CMutiTextureDD_OpenGL()
{
  return new CMutiTextureDD_OpenGL;
}